/*
 * @Author: hongbin
 * @Date: 2022-09-07 15:44:29
 * @LastEditors: hongbin
 * @LastEditTime: 2022-09-07 16:01:10
 * @Description:电脑模型
 */
import { GLTF } from "three/examples/jsm/loaders/GLTFLoader";
import THREE from "../../";
import keyboard from "../../../constants/keyboard";
import { animationControl, getSize, intervalObj } from "../../helper";
import { createText, loadGltf } from "../../helper/loaderHelper";
import { acterWrap, cameraWrap } from "../../object";
import { ComputerScreenController } from "./ComputerScreen";
import { powerSwitchController } from "./PowerSwitch";

export const loadComputer = (objects: THREE.Object3D, withVolume: THREE.Object3D[], floorHeight: number) => {
    const computerScreenController = ComputerScreenController();

    const handleKeyDown = (model: THREE.Object3D, key: string) => {
        const y = model.position.y * 0.6;
        const { word } = model.userData;

        animationControl.add({
            part: 10,
            count: 0,
            callback: function () {
                const increase = (y / this.part) * (this.count < this.part / 2 ? -1 : 1);
                model.position.y += increase;
                word.position.y += increase;
                this.count++;
            },
        });
    };

    /**
     * 键盘上的字母
     */
    const renderWord = (name: string, length: number, mini: boolean) => {
        const size = name === "space" ? 3 : name.length >= 2 ? 1.4 : 2;
        const word = createText(name, {
            size,
            height: 0.2,
            curveSegments: 0.02,
            bevelThickness: 0.02,
            bevelSize: 0.01,
        });
        word.rotation.x = -Math.PI / 2;
        const { x } = getSize(word);
        word.position.set(-x / 2 / length, 0.6, 1);
        if (mini) {
            word.position.x -= length;
        }
        return word;
    };
    /**
     * 键盘按键
     */
    const renderKey = (
        row: typeof keyboard[number],
        rowIndex: number,
        container: THREE.Object3D,
        keyModel: THREE.Object3D,
        layout: { width: number; height: number; space: number }
    ) => {
        let startX = 0;
        const { width, height, space } = layout;
        row.forEach(({ name, length = 1, children, mini }, index) => {
            const key = new THREE.Group();
            container.add(key);
            if (children) {
                renderKey(children, rowIndex, key, keyModel, layout);
                key.position.set(startX, 0, rowIndex * (height + space));
                startX += width * length + space;
                key.position.x += ((length - 1) * width) / 2;
            } else {
                const press = keyModel.clone();
                const word = renderWord(name, length, !!mini);
                if (mini) {
                    key.position.set(0, 0, (index * height) / 2 - height / 4);
                    press.scale.z /= 2;
                } else {
                    key.position.set(startX, 0, rowIndex * (height + space));
                }
                press.scale.x *= length;

                startX += width * length + space;
                key.position.x += ((length - 1) * width) / 2;
                //先放到键中获取应该出现的位置
                press.add(word);
                key.add(press);

                //保存应该出现的位置
                //移出键 不进行碰撞检测 减小开销 防止掉帧
                requestAnimationFrame(() => {
                    const { x, y, z } = word.getWorldPosition(new THREE.Vector3());
                    press.remove(word);
                    word.position.set(x, y - floorHeight, z);
                    word.scale.x /= 1.615;
                    word.scale.y /= 1.47;
                    if (mini) {
                        word.scale.y /= 2;
                    }
                    objects.add(word);
                });

                press.userData = intervalObj(
                    {
                        name,
                        word,
                        effect: function () {
                            computerScreenController.input(name);
                            handleKeyDown(press, name);
                        },
                    },
                    500
                );
            }
        });
    };

    const renderComputer = (gltf: GLTF) => {
        const computer = gltf.scene;

        withVolume.push(computer);
        objects.add(computer);
        computer.position.set(0, -2.5, -120);
        /**
         * 电源开关🔌
         */
        const powerSwitch = computer.getObjectByName("switch");
        // const powerSwitch = undefined as any;
        if (powerSwitch) {
            //注册事件监听
            powerSwitchController.init(powerSwitch, (isOff) => {
                /**
                 * 处理开关机逻辑
                 */
                powerSwitch.userData["off"] = isOff;
                console.log(isOff ? "关机了" : "开机了");
                const key = isOff ? "turnOff" : "turnOn";
                computerScreenController[key]();
                /**
                 * 开关按下
                 */
                const increase = 0.05 * (isOff ? 1 : -1);
                animationControl.add({
                    part: 10,
                    count: 0,
                    callback: function () {
                        powerSwitch.position.y += increase;
                        //向上顶起时会穿模 人物需同步移动
                        if (isOff) {
                            acterWrap.position.y += increase;
                            cameraWrap.position.y += increase;
                        }
                        this.count++;
                    },
                });
            });
            objects.add(powerSwitchController.toast);
            powerSwitch.userData = intervalObj(
                {
                    off: true,
                    timer: null,
                    effect: function () {
                        powerSwitchController.toast.userData.off = powerSwitch.userData.off;
                        powerSwitchController.toast.userData.show();
                        clearTimeout(powerSwitch.userData.timer);
                        powerSwitch.userData.timer = setTimeout(() => {
                            powerSwitchController.toast.userData.hidden();
                        }, 400);
                    },
                },
                300
            );
        }

        /**
         * 屏幕注册
         */
        const screenModel = computer.getObjectByName("screen");
        if (screenModel) {
            computerScreenController.init(screenModel);
        }

        /**
         * 键盘生成设置
         */
        const keyModel = computer.getObjectByName("key");
        const keyboardModel = computer.getObjectByName("keyboard");

        if (!keyModel || !keyboardModel) return;
        computer.remove(keyModel);
        const space = 0.5;
        const { x: width, z: height } = getSize(keyModel);
        const keys = new THREE.Group();
        keys.position.set(14, 1.3, -70);
        keys.scale.set(1.315, 1, 1.47);
        keys.rotation.x = 0.023;
        keyboardModel.add(keys);
        // keyboardModel.scale.set(2, 2, 2);

        keyboard.forEach((row, index) => renderKey(row, index, keys, keyModel, { width, height, space }));
        window.render();
    };
    /**
     * 电脑模型加载
     */
    loadGltf("api/glb?name=computer.glb")
        .then(renderComputer)
        .catch((err) => {
            console.log("err", err);
        });
};
